// 
// Copyright (C) 2000-2003
// magustek co.
//

#ifndef MAGUS_CONDITION_HPP
#define MAGUS_CONDITION_HPP

#include <magus/config.hpp>
#include <magus/utility.hpp>
#include <magus/thread/exceptions.hpp>
#include <magus/thread/detail/lock.hpp>
#include <magus/thread/detail/config.hpp>
#include <magus/thread/detail/condition_impl.hpp>

#if defined(MAGUS_HAS_PTHREADS)
#   include <pthread.h>
#endif

namespace magus {
	
struct xtime;

class condition : private noncopyable
{
public:
    condition() { }
    ~condition() { }

    void notify_one() { m_impl.notify_one(); }
    void notify_all() { m_impl.notify_all(); }

    template <typename L>
    void wait(L& lock)
    {
        if (!lock)
            throw lock_error();

        do_wait(lock.m_mutex);
    }

    template <typename L, typename Pr>
    void wait(L& lock, Pr pred)
    {
        if (!lock)
            throw lock_error();

        while (!pred())
            do_wait(lock.m_mutex);
    }

    template <typename L>
    bool timed_wait(L& lock, const xtime& xt)
    {
        if (!lock)
            throw lock_error();

        return do_timed_wait(lock.m_mutex, xt);
    }

    template <typename L, typename Pr>
    bool timed_wait(L& lock, const xtime& xt, Pr pred)
    {
        if (!lock)
            throw lock_error();

        while (!pred())
        {
            if (!do_timed_wait(lock.m_mutex, xt))
                return false;
        }

        return true;
    }

private:
    detail::condition_impl m_impl;

    template <typename M>
    void do_wait(M& mutex)
    {
#if defined(MAGUS_HAS_WINTHREADS)
        m_impl.enter_wait();
#endif

        typedef detail::thread::lock_ops<M> 
        lock_ops;

        typename lock_ops::lock_state state;
        lock_ops::unlock(mutex, state);

#if defined(MAGUS_HAS_PTHREADS)
        m_impl.do_wait(state.pmutex);
#elif defined(MAGUS_HAS_WINTHREADS)
        m_impl.do_wait();
#endif

        lock_ops::lock(mutex, state);
#undef lock_ops
    }

    template <typename M>
    bool do_timed_wait(M& mutex, const xtime& xt)
    {
#if defined(MAGUS_HAS_WINTHREADS)
        m_impl.enter_wait();
#endif

        typedef detail::thread::lock_ops<M>
        lock_ops;

        typename lock_ops::lock_state state;
        lock_ops::unlock(mutex, state);

        bool ret = false;

#if defined(MAGUS_HAS_PTHREADS)
        ret = m_impl.do_timed_wait(xt, state.pmutex);
#elif defined(MAGUS_HAS_WINTHREADS)
        ret = m_impl.do_timed_wait(xt);
#endif

        lock_ops::lock(mutex, state);
#undef lock_ops

        return ret;
    }
    
}; // class condition

} // namespace magus

// Change Log:
//    16 JUN 03  Initial version.

#endif // MAGUS_CONDITION_HPP
